#ifndef _endian_hpp_
#define _endian_hpp_

/** \file endian.hpp
 *  \author Adrian Schweizer
 *  \brief contains the 3 utility routines swap_endian, local_to_net, net_to_local which assist in endian conversions
 *  for numeric types of arbitrary > 1 byte length
 *  \created  $Sa 18 Aug 04:25:33 pm CEST 2007 schwadri@SchwadriComp.local$
 *  \modified $Do 30 Aug 12:20:20 pm CEST 2007 schwadri@SchwadriComp.local$
 */

#include <algorithm>

namespace core {

    namespace encoding {

        namespace detail {

            template<int N>
                struct conversion_helper
                {
                    static void apply(unsigned char* value)
                    {
                        using std::swap;
                        swap(*value,*(value+N-1));
                        conversion_helper<N-2>::apply(value+1);
                    }
                };

            template<>
                struct conversion_helper<2>
                {
                    static void apply(unsigned char* value)
                    {
                        using std::swap;
                        swap(*value,*(value+1));
                    }
                };
            template<>
                struct conversion_helper<3>;    // error: this should not be instanciated

            template<>
                struct conversion_helper<1>    // this does nothing
                {
                    static void apply(unsigned char* value)
                    { }
                };

        }

        /** \brief swap endianess of a generic numeric type
         *
         *  \param[in] value  a numeric value
         *  \return the same value with its byte order reversed
         *  \warning works only with types that have a length of 2*n bytes
         */
        template<class T>
            T   swap_endian(const T& value)
            {
                T   temp(value);

                detail::conversion_helper<sizeof(T)>::apply(reinterpret_cast<unsigned char*>(&temp));
                return temp;
            }

        /** \brief convert a value from local to network byte order
         *
         *  \sa swap_endian
         */
        template<class T>
            T   local_to_net(const T& value)
            {
            #ifndef __BIG_ENDIAN__
                return swap_bytes(value);
            #else
                return value;
            #endif
            }

        /** \brief convert a value from network to local byte order 
         *
         *  \sa swap_endian
         */
        template<class T>
            T   net_to_local(const T& value)
            {
            #ifndef __BIG_ENDIAN__
                return swap_bytes(value);
            #else
                return value;
            #endif
            }
    } // namespace encoding

}   // namespace core
#endif // _endian_hpp_
